package com.tangtang.core;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Properties;

/**
 * 用来加载类，classPath下的资源文件，属性文件等。
 * getExtendResource(String relativePath)方法，可以使用../符号来加载classpath外部的资源。
 */
public class ClassLoaderUtil {
    /**
     * 加载Java类。 使用全限定类名
     *
     * @return
     * @paramclassName
     */
    public static Class<?> loadClass(String className) {
        try {
            return getClassLoader().loadClass(className);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException("class not found '" + className + "'", e);
        }
    }

    /**
     * 得到类加载器
     *
     * @return
     */
    public static ClassLoader getClassLoader() {
        return ClassLoaderUtil.class.getClassLoader();
    }

    /**
     * 提供相对于classpath的资源路径，返回文件的输入流
     *
     * @param relativePath 必须传递资源的相对路径 。是相对于classpath的路径。如果需要查找classpath外部的资源，需要使用../来查找
     * @return 文件输入流
     * @throws IOException
     * @throws MalformedURLException
     */
    public static InputStream getStream(String relativePath)
            throws IOException {
        if (!relativePath.contains("../")) {
            return getClassLoader().getResourceAsStream(relativePath);

        } else {
            return getStreamByExtendResource(relativePath);
        }
    }

    /**
     * @return
     * @paramurl
     * @throwsIOException
     */
    public static InputStream getStream(URL url) throws IOException {
        if (url != null) {
            return url.openStream();
        } else {
            return null;
        }
    }

    /**
     * @return InputStream
     * @paramrelativePath必须传递资源的相对路径。是相对于classpath的路径。如果需要查找classpath外部的资源，需要使用../来查找
     * @throwsIOException
     */
    public static InputStream getStreamByExtendResource(String relativePath)
            throws IOException {
        return getStream(
                getExtendResource(relativePath));
    }

    /**
     * 提供相对于classpath的资源路径，返回属性对象，它是一个散列表
     *
     * @param resource
     * @return
     */
    public static Properties getProperties(String resource) {
        Properties properties = new Properties();
        try {
            properties.load(getStream(resource));
        } catch (IOException e) {
            throw new RuntimeException("couldn't load properties file '"
                    + resource + "'", e);
        }
        return properties;
    }

    /**
     * 得到本Class所在的ClassLoader的Classpat的绝对路径。 URL形式的
     *
     * @return AbsolutePathOfClassLoaderClassPath
     */
    public static String getAbsolutePathOfClassLoaderClassPath() {
        return getClassLoader().getResource("").toString();
    }

    /**
     * @return 资源的绝对URL
     * @throws MalformedURLException
     * @paramrelativePath 必须传递资源的相对路径。是相对于classpath的路径。如果需要查找classpath外部的资源，需要使用../来查找
     */
    public static URL getExtendResource(String relativePath)
            throws MalformedURLException {

        if (!relativePath.contains("../")) {
            return getResource(relativePath);
        }
        String classPathAbsolutePath =
                getAbsolutePathOfClassLoaderClassPath();
        if (relativePath.substring(0, 1).equals("/")) {
            relativePath = relativePath.substring(1);
        }

        String wildcardString = relativePath.substring(0,
                relativePath.lastIndexOf("../") + 3);
        relativePath = relativePath
                .substring(relativePath.lastIndexOf("../") + 3);
        int containSum = containSum(wildcardString, "../");
        classPathAbsolutePath = cutLastString(
                classPathAbsolutePath, "/", containSum);
        String resourceAbsolutePath = classPathAbsolutePath + relativePath;
        URL resourceAbsoluteURL = new URL(resourceAbsolutePath);
        return resourceAbsoluteURL;
    }

    /**
     * @param source orignal words
     * @param dest   destination
     * @return times matched
     */
    private static int containSum(String source, String dest) {
        int containSum = 0;
        int destLength = dest.length();
        while (source.contains(dest)) {
            containSum = containSum + 1;
            source = source.substring(destLength);
        }

        return containSum;
    }

    /**
     * @param source
     * @param dest
     * @param num
     * @return
     */
    private static String cutLastString(String source, String dest, int num) {
        // String cutSource=null;
        for (int i = 0; i < num; i++) {
            source = source.substring(0,
                    source.lastIndexOf(dest, source.length() - 2) + 1);
        }
        return source;
    }

    /**
     * @param resource resource
     * @return URL
     */
    public static URL getResource(String resource) {
        return getClassLoader().getResource(resource);
    }
}